{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "jLQ7lbhwrGFA",
      "metadata": {
        "id": "jLQ7lbhwrGFA"
      },
      "source": [
        "# Build an e-commerce recommendation AI agents with ADK + Vector Search\n",
        "\n",
        "Original Author(s): [Kaz Sato](https://github.com/kazunori279)\n",
        "\n",
        "In this tutorial, we will explore how to build a simple multi-agent system for an e-commerce site, designed to offer the \"Generative Recommendations\" you find in the [Shopper's Concierge demo](https://www.youtube.com/watch?v=LwHPYyw7u6U). A step-by-step guide video is also available [here](https://youtu.be/07GX28rk7Yc).\n",
        "\n",
        "### What is Generative Recommendation?\n",
        "\n",
        "Generative Recommendation refers to the AI's ability to not only retrieve items directly matching a user's explicit search query but also to **intelligently infer, expand upon, or create new search queries and item suggestions based on a deeper understanding of the user's intent, external research, or contextual information.**\n",
        "\n",
        "Here's a breakdown of its capabilities as demonstrated:\n",
        "\n",
        "1.  **Understanding and Expanding User Intent:** Instead of simply taking a direct query, the system can interpret the underlying need. For instance, when a user asks for a \"birthday present for 10 years old boy,\" the AI doesn't just search for those exact keywords.\n",
        "2.  **Leveraging External Research (Google Search):** The \"Generative Recommendation\" process involves using tools like Google Search to perform market research. This allows the AI to understand what kind of items are generally purchased for a given intent (e.g., popular gifts for 10-year-old boys).\n",
        "3.  **Generating New Queries:** Based on this research, the AI actively *generates* a list of more specific and diverse search queries. These generated queries go beyond the initial user input, aiming to broaden the search and find more relevant results (e.g., \"educational toys for 10-year-olds,\" \"adventure books for boys,\" \"coding kits for kids\").\n",
        "\n",
        "In essence, \"Generative Recommendation\" moves beyond simple keyword matching to a more dynamic and intelligent approach where the AI proactively assists the user by generating new ideas and relevant search paths to help them discover desired products.\n",
        "\n",
        "In the end, we will build an agent system that works in the following flow:\n",
        "\n",
        "![Shop agent sequence diagram](../../../docs/assets/shop_agent.png)\n",
        "\n",
        "<!-- Mermaid code for the diagram\n",
        "sequenceDiagram\n",
        "   participant User\n",
        "   participant Shop Agent\n",
        "   participant Research Agent\n",
        "   participant Google Search\n",
        "   participant find_shopping_items\n",
        "   participant Vector Search\n",
        "\n",
        "   User->>Shop Agent: Any birthday present for my son?\n",
        "   activate Shop Agent\n",
        "   Shop Agent->>Research Agent: Any birthday present for my son?\n",
        "   activate Research Agent\n",
        "   Research Agent->>Google Search: search on birthday presents for boys\n",
        "   activate Google Search\n",
        "   Google Search->>Research Agent: search results\n",
        "   deactivate Google Search\n",
        "   Research Agent->>Research Agent: generate 5 queries\n",
        "   Research Agent->>Shop Agent: \"STEM Toys\", \"Lego sets\"...\n",
        "   deactivate Research Agent\n",
        "   Shop Agent->>User: Here are the suggested queries: \"STEM Toys\", \"Lego sets\"...\n",
        "   Shop Agent->>User: Is it OK to search with those queries?\n",
        "   deactivate Shop Agent\n",
        "\n",
        "   activate Shop Agent\n",
        "   User->>Shop Agent: Yes, please!\n",
        "   activate find_shopping_items\n",
        "   Shop Agent->>find_shopping_items: \"STEM Toys\", \"Lego sets\"...\n",
        "   activate Vector Search\n",
        "   find_shopping_items->>Vector Search: \"STEM Toys\", \"Lego sets\"...\n",
        "   Vector Search->>find_shopping_items: \"Kids Walkie talkies\", \"Minecraft Explorers Pack\"...\n",
        "   deactivate Vector Search\n",
        "   find_shopping_items->>Shop Agent : \"Kids Walkie talkies\", \"Minecraft Explorers Pack\"...\n",
        "   deactivate find_shopping_items\n",
        "   Shop Agent->>User : \"Kids Walkie talkies\", \"Minecraft Explorers Pack\"...\n",
        "   deactivate Shop Agent\n",
        "-->"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ZyK62QElQv_K",
      "metadata": {
        "id": "ZyK62QElQv_K"
      },
      "source": [
        "## Install ADK\n",
        "\n",
        "First, we will install the ADK. In Colab Enterprise, you may see `ERROR: pip's dependency resolver does...` but you can ignore it."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "id": "oeSkwKPttGh5YTX79KT9oM0E",
      "metadata": {
        "id": "oeSkwKPttGh5YTX79KT9oM0E",
        "tags": []
      },
      "outputs": [],
      "source": [
        "%pip install --upgrade google-adk==1.4.2 -q"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "WoqdAfBRrRcR",
      "metadata": {
        "id": "WoqdAfBRrRcR"
      },
      "source": [
        "### Import the libraries"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "M22ecOwlgdYZ",
      "metadata": {
        "id": "M22ecOwlgdYZ"
      },
      "outputs": [],
      "source": [
        "# Import necessary libraries\n",
        "import os\n",
        "import logging\n",
        "import asyncio\n",
        "from google.adk.agents import Agent\n",
        "from google.adk.runners import Runner\n",
        "from google.adk.sessions import  InMemorySessionService\n",
        "from google.adk.tools.agent_tool import AgentTool\n",
        "from google.genai import types\n",
        "\n",
        "# Ignore warnings from ADK and Gemini APIs\n",
        "logging.getLogger(\"google.adk.runners\").setLevel(logging.ERROR)\n",
        "logging.getLogger(\"google_genai.types\").setLevel(logging.ERROR)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "11963108",
      "metadata": {},
      "source": [
        "### Set environment variables\n",
        "\n",
        "Get an API key from [Google AI Studio](https://aistudio.google.com/apikey), set the key to the following `GOOGLE_API_KEY`, and run the cell to set the environment variables required for running ADK."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bb4b79a7",
      "metadata": {},
      "outputs": [],
      "source": [
        "from getpass import getpass\n",
        "\n",
        "# Set environment variables required for running ADK (with Gemini API Key)\n",
        "os.environ[\"GOOGLE_GENAI_USE_VERTEXAI\"] = \"False\"\n",
        "os.environ[\"GOOGLE_API_KEY\"] = getpass(\"Enter your Gemini API Key: \")\n",
        "\n",
        "# To use Vertex AI instead of Gemini API Key in Colab Enterprise or Cloud Workbench, use the following:\n",
        "#[PROJECT_ID] = !gcloud config list --format \"value(core.project)\"\n",
        "#os.environ[\"GOOGLE_CLOUD_PROJECT\"] = PROJECT_ID\n",
        "#os.environ[\"GOOGLE_CLOUD_LOCATION\"] = \"us-central1\"\n",
        "#os.environ[\"GOOGLE_GENAI_USE_VERTEXAI\"] = \"True\""
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ynPYDwqjrVaa",
      "metadata": {
        "id": "ynPYDwqjrVaa"
      },
      "source": [
        "## Define **test_agent** function for testing agents\n",
        "\n",
        "For testing the agents we will build, we need to define a function `test_agent` that uses `Runner` and `SessionService` to emulate an agent runtime environment. To learn more about the agent runtime, see the [Agent Runtime](https://google.github.io/adk-docs/runtime/) doc."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "DFy28Xv38Ngu",
      "metadata": {
        "id": "DFy28Xv38Ngu"
      },
      "outputs": [],
      "source": [
        "from google.genai import types\n",
        "\n",
        "# Define the app_name, user_id and session_id for testing the agents\n",
        "APP_NAME = \"shop_concierge_app\"\n",
        "USER_ID = \"user_1\"\n",
        "\n",
        "session_service = InMemorySessionService()\n",
        "\n",
        "async def test_agent(query, agent):\n",
        "  \"\"\"Sends a query to the agent and prints the final response.\"\"\"\n",
        "\n",
        "  print(f\"\\n>>> User Query: {query}\")\n",
        "\n",
        "  # Create a session\n",
        "  session = await session_service.create_session(\n",
        "    app_name=APP_NAME,\n",
        "    user_id=USER_ID,\n",
        "  )\n",
        "\n",
        "  # Create a Runner\n",
        "  runner = Runner(\n",
        "      app_name=APP_NAME,\n",
        "      agent=agent,\n",
        "      session_service=session_service,\n",
        "  )\n",
        "\n",
        "  # Prepare the user's message in ADK format\n",
        "  content = types.Content(role='user', parts=[types.Part(text=query)])\n",
        "\n",
        "  final_response_text = None\n",
        "  # We iterate through events from run_async to find the final answer.\n",
        "  async for event in runner.run_async(user_id=USER_ID, session_id=session.id, new_message=content):\n",
        "      if event.is_final_response():\n",
        "          if event.content and event.content.parts:\n",
        "             final_response_text = event.content.parts[0].text\n",
        "          break\n",
        "  print(f\"<<< Agent Response: {final_response_text}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "TcVBA98xra0i",
      "metadata": {
        "id": "TcVBA98xra0i"
      },
      "source": [
        "## Define an **Shop agent**\n",
        "\n",
        "Let's define a shop agent and test it. Note that this agent does not have any search capability at this time."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "em9XplVkggtO",
      "metadata": {
        "id": "em9XplVkggtO"
      },
      "outputs": [],
      "source": [
        "instruction = f'''\n",
        "    Your role is a shop search agent on an e-commerce site with millions of\n",
        "    items. Your responsibility is to search items based on user queries.\n",
        "'''\n",
        "\n",
        "shop_agent = Agent(\n",
        "    model='gemini-2.5-flash',\n",
        "    name='shop_agent',\n",
        "    description=(\n",
        "        'Shop agent for an e-commerce site'\n",
        "    ),\n",
        "    instruction=instruction,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "aJGpLk7P-BQP",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "aJGpLk7P-BQP",
        "outputId": "55606e8e-f663-4f7c-c1fb-1af5a5ec6817"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            ">>> User Query: What kind of site is this?\n",
            "<<< Agent Response: I am a shop agent for an e-commerce site with millions of items.\n",
            "\n"
          ]
        }
      ],
      "source": [
        "await test_agent(\"What kind of site is this?\", shop_agent)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "zcJJw0m6re_K",
      "metadata": {
        "id": "zcJJw0m6re_K"
      },
      "source": [
        "## Define **call_vector_search** to call the Vector Search backend\n",
        "\n",
        "With the basic agent above, we would like to add an item search capability. To achieve this, here we define a function `call_query_api` that sends an HTTP request to a REST endpoint provided by the [Vector Search Interactive demo](https://cloud.google.com/vertex-ai/docs/vector-search/try-it). For the detail of each parameter sent to the endpoint, refer to the demo page."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "y75WYLNchHPD",
      "metadata": {
        "id": "y75WYLNchHPD"
      },
      "outputs": [],
      "source": [
        "import requests\n",
        "import json\n",
        "\n",
        "def call_vector_search(url, query, rows=None):\n",
        "    \"\"\"\n",
        "    Calls the Vector Search backend for querying.\n",
        "\n",
        "    Args:\n",
        "        url (str): The URL of the search endpoint.\n",
        "        query (str): The query string.\n",
        "        rows (int, optional): The number of result rows to return. Defaults to None.\n",
        "\n",
        "    Returns:\n",
        "        dict: The JSON response from the API.\n",
        "    \"\"\"\n",
        "\n",
        "    # Build HTTP headers and a payload\n",
        "    headers = {'Content-Type': 'application/json'}\n",
        "    payload = {\n",
        "        \"query\": query,\n",
        "        \"rows\": rows,\n",
        "        \"dataset_id\": \"mercari3m_mm\", # Use Mercari 3M multimodal index\n",
        "        \"use_dense\": True, # Use multimodal search\n",
        "        \"use_sparse\": True, # Use keyword search too\n",
        "        \"rrf_alpha\": 0.5, # Both results are merged with the same weights\n",
        "        \"use_rerank\": True, # Use Ranking API for reranking\n",
        "    }\n",
        "\n",
        "    # Send an HTTP request to the search endpoint\n",
        "    try:\n",
        "        response = requests.post(url, headers=headers, data=json.dumps(payload))\n",
        "        response.raise_for_status()  # Raise an exception for bad status codes\n",
        "        return response.json()\n",
        "    except requests.exceptions.RequestException as e:\n",
        "        print(f\"Error calling the API: {e}\")\n",
        "        return None"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "VQzZRzYdrtKg",
      "metadata": {
        "id": "VQzZRzYdrtKg"
      },
      "source": [
        "## Define **find_shopping_items** tool\n",
        "\n",
        "Now, we will wrap the `call_vector_search` function with an ADK Tool named `find_shopping_items`. Note that we need to 1) use the explicit typing such as `queries: list[str]` and 2) use the verbose docstring, both for conveying the functionality and semantics of this Tool to the agent.\n",
        "\n",
        "For details of the Tool mechanism of ADK, refer to the [Tools](https://google.github.io/adk-docs/tools/) in the ADK docs."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "D7Vj4_-aiykD",
      "metadata": {
        "id": "D7Vj4_-aiykD"
      },
      "outputs": [],
      "source": [
        "from typing import Dict\n",
        "\n",
        "def find_shopping_items(queries: list[str]) -> Dict[str, str]:\n",
        "    \"\"\"\n",
        "    Find shopping items from the e-commerce site with the specified list of\n",
        "    queries.\n",
        "\n",
        "    Args:\n",
        "        queries: the list of queries to run.\n",
        "    Returns:\n",
        "        A dict with the following one property:\n",
        "            - \"status\": returns the following status:\n",
        "                - \"success\": successful execution\n",
        "            - \"items\": items found in the e-commerce site.\n",
        "    \"\"\"\n",
        "    url = \"https://www.ac0.cloudadvocacyorg.joonix.net/api/query\"\n",
        "\n",
        "    items = []\n",
        "    for query in queries:\n",
        "        result = call_vector_search(\n",
        "            url=url,\n",
        "            query=query,\n",
        "            rows=3,\n",
        "        )\n",
        "        items.extend(result[\"items\"])\n",
        "\n",
        "    print(\"-----\")\n",
        "    print(f\"User queries: {queries}\")\n",
        "    print(f\"Found: {len(items)} items\")\n",
        "    print(\"-----\")\n",
        "\n",
        "    return items"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "_2bMByoWX8De",
      "metadata": {
        "id": "_2bMByoWX8De"
      },
      "source": [
        "Let's test this tool."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "KMWwG9CJl0zR",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "KMWwG9CJl0zR",
        "outputId": "aed8653b-1519-4e46-ff59-7cf0b168610b"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "-----\n",
            "User queries: ['Cups with dancing people', 'Cups with dancing animals']\n",
            "Found: 6 items\n",
            "-----\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "[{'dense_dist': 0.0,\n",
              "  'description': 'Free People Womens Sunset Dancing Dress Pink Size M\\n\\nBrand : Free People \\nStyle : Sunset Dancing Dress\\nColor : Pink\\nSize : M\\nSku No : 9968\\ncondition : New Without Tag\\nBeaded tie detail\\nLadder lace insert at waist\\nFully lined',\n",
              "  'id': 'm47216877271',\n",
              "  'img_url': 'https://u-mercari-images.mercdn.net/photos/m47216877271_1.jpg?w=200&h=200&fitcrop&sharpen',\n",
              "  'name': 'Free People Womens Sunset Dancing Dress Pink Size M',\n",
              "  'rerank_score': 0.0,\n",
              "  'sparse_dist': 0.4827784597873688,\n",
              "  'url': 'https://www.mercari.com/us/item/m47216877271'},\n",
              " {'dense_dist': 0.20211432874202728,\n",
              "  'description': 'Vintage hardanger dancer bergquist figgjo coffee mugs',\n",
              "  'id': 'm10172014563',\n",
              "  'img_url': 'https://u-mercari-images.mercdn.net/photos/m10172014563_1.jpg?w=200&h=200&fitcrop&sharpen',\n",
              "  'name': 'Vintage Berquist Figgjo coffee mugs',\n",
              "  'rerank_score': 0.0,\n",
              "  'sparse_dist': None,\n",
              "  'url': 'https://www.mercari.com/us/item/m10172014563'},\n",
              " {'dense_dist': 0.1960698664188385,\n",
              "  'description': 'Pottery Barn Christmas Reindeer Mugs - Dasher, Dancer, Prancer & Vixen Set of 4',\n",
              "  'id': 'm81366738028',\n",
              "  'img_url': 'https://u-mercari-images.mercdn.net/photos/m81366738028_1.jpg?w=200&h=200&fitcrop&sharpen',\n",
              "  'name': 'Pottery barn reindeer mugs',\n",
              "  'rerank_score': 0.0,\n",
              "  'sparse_dist': None,\n",
              "  'url': 'https://www.mercari.com/us/item/m81366738028'},\n",
              " {'dense_dist': 0.0,\n",
              "  'description': 'Brand new / dancing figure',\n",
              "  'id': 'm11326867382',\n",
              "  'img_url': 'https://u-mercari-images.mercdn.net/photos/m11326867382_1.jpg?w=200&h=200&fitcrop&sharpen',\n",
              "  'name': 'Hello Kitty Dancing figure',\n",
              "  'rerank_score': 0.0,\n",
              "  'sparse_dist': 0.4476025104522705,\n",
              "  'url': 'https://www.mercari.com/us/item/m11326867382'},\n",
              " {'dense_dist': 0.25508207082748413,\n",
              "  'description': 'Gold rim on top\\nNo cracks or chips \\nExcellent condition \\nNo marks inside cup\\nLike new\\nNon smoking home',\n",
              "  'id': 'm71882643462',\n",
              "  'img_url': 'https://u-mercari-images.mercdn.net/photos/m71882643462_1.jpg?w=200&h=200&fitcrop&sharpen',\n",
              "  'name': 'VINTAGE Walt Disney ARISTOCATS Gold Rim Coffee Mugs Cup Teacup (Japan)',\n",
              "  'rerank_score': 0.0,\n",
              "  'sparse_dist': None,\n",
              "  'url': 'https://www.mercari.com/us/item/m71882643462'},\n",
              " {'dense_dist': 0.0,\n",
              "  'description': 'The best of the animals',\n",
              "  'id': 'm30120116854',\n",
              "  'img_url': 'https://u-mercari-images.mercdn.net/photos/m30120116854_1.jpg?w=200&h=200&fitcrop&sharpen',\n",
              "  'name': 'The animals record(original)',\n",
              "  'rerank_score': 0.0,\n",
              "  'sparse_dist': 0.4455285668373108,\n",
              "  'url': 'https://www.mercari.com/us/item/m30120116854'}]"
            ]
          },
          "execution_count": 25,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "find_shopping_items([\"Cups with dancing people\", \"Cups with dancing animals\"])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "S1E0TEB7ryBe",
      "metadata": {
        "id": "S1E0TEB7ryBe"
      },
      "source": [
        "## Add the tool to **Shop agent**\n",
        "\n",
        "It's ready to add the Tool to the Shop agent. The following parts are added:\n",
        "\n",
        "- Addition to the `instruction`: `To find items use find_shopping_items tool by passing a list of queries, and answer to the user with item's name, description and img_url`\n",
        "- Adding `tools` parameter to the `Agent` constructor: `tools=[find_shopping_items]`\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "sHVv95QUnDHE",
      "metadata": {
        "id": "sHVv95QUnDHE"
      },
      "outputs": [],
      "source": [
        "instruction = f'''\n",
        "    Your role is a shop search agent on an e-commerce site with millions of\n",
        "    items. Your responsibility is to search items based on the queries you\n",
        "    recieve.\n",
        "\n",
        "    To find items use `find_shopping_items` tool by passing a list of queries,\n",
        "    and answer to the user with item's name, description and img_url\n",
        "'''\n",
        "\n",
        "shop_agent = Agent(\n",
        "    model='gemini-2.5-flash',\n",
        "    name='shop_agent',\n",
        "    description=(\n",
        "        'Shop agent for an e-commerce site'\n",
        "    ),\n",
        "    instruction=instruction,\n",
        "    tools=[find_shopping_items],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "Q2jMH45yY540",
      "metadata": {
        "id": "Q2jMH45yY540"
      },
      "source": [
        "Let's test the agent."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "L4CpsCzWnfIj",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "L4CpsCzWnfIj",
        "outputId": "51d60d11-67e0-4979-98a2-6513cd21d028"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            ">>> User Query: Cups with dancing figures\n",
            "-----\n",
            "User queries: ['Cups with dancing figures']\n",
            "Found: 3 items\n",
            "-----\n",
            "<<< Agent Response: I found three items that match your description:\n",
            "\n",
            "*   **Easter Decor Dancing Solar items lot of 4 Solar Figures:** This is a set of 4 solar-powered Easter decorations featuring dancing figures. The set includes a dancing rabbit in an egg, a dancing male bunny in a car, a dancing girl bunny in a car, and a dancing hatching chicken. They are 4.5 inches tall.\n",
            "*   **Mayfair Collection By Jay-African Ladies/Baskets/Sun- Tea/Coffee Cup/Mug:** This mug features African ladies, baskets, and the sun. The mug is in very good pre-owned condition with no cracks, chips, crazing, or visible scratches. It is 4.25\" tall x 4.5\" wide with handle x 3.25\" across.\n",
            "*   **Hello Kitty Dancing figure:** This is a brand new Hello Kitty dancing figure.\n"
          ]
        }
      ],
      "source": [
        "await test_agent(\"Cups with dancing figures\", shop_agent)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "IoKVQ8vcr2zL",
      "metadata": {
        "id": "IoKVQ8vcr2zL"
      },
      "source": [
        "## Define **Research agent** with Google Search grounding\n",
        "\n",
        "Next, we will define another agent `research_agent`. This agent will take the user query and use the built-in Google Search tool for researching on what kind of items people are purchasing for the user's intent. Then generate 5 queries for finding those items.\n",
        "\n",
        "Note that the following agent definition specifies `google_search` as a tool. With this, the agent obtains a capability to use Google Search. For details about the Google Search tool, refer to [Google Search](https://google.github.io/adk-docs/tools/built-in-tools/#google-search) on the ADK docs."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "cL-EDlNtoRk5",
      "metadata": {
        "id": "cL-EDlNtoRk5"
      },
      "outputs": [],
      "source": [
        "from google.adk.tools import google_search\n",
        "\n",
        "instruction = f'''\n",
        "    Your role is a market researcher for an e-commerce site with millions of\n",
        "    items.\n",
        "\n",
        "    When you recieved a search request from an user, use Google Search tool to\n",
        "    research on what kind of items people are purchasing for the user's intent.\n",
        "\n",
        "    Then, generate 5 queries finding those items on the e-commerce site and\n",
        "    return them.\n",
        "'''\n",
        "\n",
        "research_agent = Agent(\n",
        "    model='gemini-2.5-flash',\n",
        "    name='research_agent',\n",
        "    description=('''\n",
        "        A market researcher for an e-commerce site. Receives a search request\n",
        "        from a user, and returns a list of 5 generated queries in English.\n",
        "    '''),\n",
        "    instruction=instruction,\n",
        "    tools=[google_search],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "-i3ou53eivrP",
      "metadata": {
        "id": "-i3ou53eivrP"
      },
      "source": [
        "Let's test the agent."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "0FYYM9zLpJ2L",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0FYYM9zLpJ2L",
        "outputId": "e2f276cd-5368-4452-96f0-925f3dae48a1"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            ">>> User Query: birthday present for 10 years old boy\n",
            "<<< Agent Response: Okay, I can help you brainstorm some gift ideas for a 10-year-old boy and then create search queries for an e-commerce site. Based on current trends and popular interests for that age group, here are some general categories:\n",
            "\n",
            "1.  **Tech Gifts/Gadgets:** This could include things like headphones, smartwatches, or beginner-friendly coding kits.\n",
            "2.  **Outdoor/Sports Equipment:** Items like a new basketball, skateboard, or camping gear are often a hit.\n",
            "3.  **Building/Construction Toys:** LEGO sets, model kits, or remote control vehicles offer engaging activities.\n",
            "4.  **Books/Games:** Consider age-appropriate books, board games, or video games.\n",
            "5.  **Arts & Crafts:** If the boy is creative, art supplies or DIY kits could be a good choice.\n",
            "\n",
            "Now, let's create 5 specific search queries for an e-commerce site based on these categories:\n",
            "\n",
            "\n"
          ]
        }
      ],
      "source": [
        "await test_agent(\"birthday present for 10 years old boy\", research_agent)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "qlgJf8sGwnDl",
      "metadata": {
        "id": "qlgJf8sGwnDl"
      },
      "source": [
        "## Finalize the **Shop agent**\n",
        "\n",
        "To wrap up, we modify the `shop_agent` to use both `reseach_agent` and `find_shopping_items` tool."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "gnsNNcSbwi5e",
      "metadata": {
        "id": "gnsNNcSbwi5e"
      },
      "outputs": [],
      "source": [
        "instruction = f'''\n",
        "    Your role is a shopper's concierge for an e-commerce site with millions of\n",
        "    items. Follow the following steps.\n",
        "\n",
        "    When you recieved a search request from an user, pass it to `research_agent`\n",
        "    tool, and receive 5 generated queries. Then, pass the list of queries to\n",
        "    `find_shopping_items` to find items. When you recieved a list of items from\n",
        "    the tool, answer to the user with item's name, description and the image url.\n",
        "'''\n",
        "\n",
        "shop_agent = Agent(\n",
        "    model='gemini-2.5-flash',\n",
        "    name='shop_agent',\n",
        "    description=(\n",
        "        'A shopper\\'s concierge for an e-commerce site'\n",
        "    ),\n",
        "    instruction=instruction,\n",
        "    tools=[\n",
        "        AgentTool(agent=research_agent),\n",
        "        find_shopping_items,\n",
        "    ],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "FQh_PCsInr7V",
      "metadata": {
        "id": "FQh_PCsInr7V"
      },
      "source": [
        "Let's test the agent. First, the user asks the agent for finding items. The Shop agent will call the Research agent for generating queries using Google Search Results."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "kFDWW2qExjnL",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "kFDWW2qExjnL",
        "outputId": "45a13cfb-a4cc-42c6-917d-8d2158f09ce9"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            ">>> User Query: Can you find birthday present for 10 years old son?\n",
            "-----\n",
            "User queries: ['STEM building kits for 10 year old boys', 'Remote control cars for kids age 10', 'Board games strategy 10 year olds', \"Kids' beginner coding games\", 'Outdoor adventure kit for 10 year old']\n",
            "Found: 15 items\n",
            "-----\n",
            "<<< Agent Response: Here are some birthday present ideas for your 10-year-old son:\n",
            "\n",
            "*   **STEM Toys:** Kids Toys for 5 Year Old Boys - 5 in 1 Take Apart Boys Toys Age 6-8 STEM Toys for 5+ Year Old Boys Trucks Transform to Robot Building Toys for Boys Gifts for Kids 5 6 7 Year Old Boy Birthday Gifts.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m72066092335\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m72066092335_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Lucky Doug Building Toys Model Airplane Set:** This building toy set includes 258 parts and pieces, such as nuts, bolts, small screwdriver, and wrench, etc., Made of metal, which can stand rough play without worrying about easy collapse. A great careful crafting STEM building kit, worth paying a little more compared to full plastic versions. This model aircraft measures over 4\" high, 13.8\" long, and 15.8\" wide.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m87990215453\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m87990215453_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Lego:** STEM Building Toys for Boys Age 8-12, Erector Set Building Blocks for 6-8 Year Old Boys, Educational Build a Robot Truck Kit. Open box / Brand new.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m81806559165\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m81806559165_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **2 remote cars and kids steps:** 2 remote control cars and Spiderman figure steps.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m82117343164\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m82117343164_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Gizmovine Remote Control Car:** Brand new in box. Yours for $40\n",
            "    [https://u-mercari-images.mercdn.net/photos/m43459589681\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m43459589681_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Remote control spider:** Fun, remote control kids toy ￼brand new.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m30244645553\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m30244645553_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Set of 5 board games:** 5 board games shown. All pieces included.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m74053293813\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m74053293813_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Tetris Board Game:** Play this old classic phone game in board game form! Just like you remember, this game is the real life version of Tetris. Play against an opponent and see who has the best strategy when placing the tiles! This game is like new!!\n",
            "    [https://u-mercari-images.mercdn.net/photos/m85724096893\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m85724096893_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Dinosaur Toys for 3-8 Year Old:** Dinosaur Toys for 3-8 Year Old Girls,Dino Projection Kids Toys for 3-8 Year Olds Girls 2 in 1 Car Toys for 2-10 Year Olds Girls,Chirstmas Xmax Easter Gifts for 2-10 Year Olds Kids Toddler Toys(Pink).\n",
            "    [https://u-mercari-images.mercdn.net/photos/m18938674867\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m18938674867_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Two Coding Books for Kids:** Two beginner coding books for kids by CoderDojo and Scratch. Bonus Cool Careers in Video Games book. Message to bundle with my other listings :).\n",
            "    [https://u-mercari-images.mercdn.net/photos/m71279767592\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m71279767592_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Thinkfun Code Programming Game Series On The Brink Core Coding Concept New, open:** Thinkfun Code Programming Game Series On The Brink Core Coding Concept. Consist of Control panel, 40 game boards (sealed), 18 movement cards (sealed), 1 robot. Perfect shape, never been used. Open box. UPC 019275019013. Age 8+.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m44341092087\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m44341092087_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Coding & Scratching for Kids:** Title: Coding & Scratching for Kids. Author: Tommy Wilson. Age: group: 7+. # of pages: 200. Read through once. In great condition. Any questions please ask!! Thank you!!.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m26012207197\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m26012207197_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Vintage 1958 Adventure with the Stars a Capital Adventure Kit A4:** Vintage 1958 Adventure with the Stars a Capital Adventure Kit.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m36091453961\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m36091453961_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Outdoor Explorer Set - Bug Catching Kit Nature Exploration Children:** Explore the Surrounding World: This Improved kids exploration kit is suitable as Christmas Present or Birthday Gift. Is one of the most interesting nature toys you could buy for your child. With 20 pieces, the kids outdoor adventure kit has everything to keep a child occupied for hours. Teach Your Kid to Read Maps: When it comes to educational games and toys for 5 year old and nature toys, the real-working compass in the KidzXplore outdoor exploration set is the tool you need to practice discovering the north and read maps. Start BIirdwatching Now: A genuine bird watching kit for kids, the outdoor adventure kit including boys binoculars is a must-have kids hiking gear item. FreeShipping.\n",
            "    [https://u-mercari-images.mercdn.net/photos/m33432731767\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m33432731767_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "*   **Outdoor adventure mix sticker bundle:** 50 piece mix outdoor adventure sticker bundle. Various sizes and images. Waterproof. Stickers are great for memories!\n",
            "    [https://u-mercari-images.mercdn.net/photos/m90713058051\\_1.jpg?w=200&h=200&fitcrop&sharpen](https://u-mercari-images.mercdn.net/photos/m90713058051_1.jpg?w=200&h=200&fitcrop&sharpen)\n",
            "\n"
          ]
        }
      ],
      "source": [
        "await test_agent(\"Can you find birthday present for 10 years old son?\", shop_agent)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "lqb5_9FOog0D",
      "metadata": {
        "id": "lqb5_9FOog0D"
      },
      "source": [
        "## Summary\n",
        "\n",
        "In this tutorial, we went through the process of constructing a multi-agent system for an e-commerce platform, focusing on \"Generative Recommendations\".\n",
        "\n",
        "Through this progression, the tutorial illustrated how to build a sophisticated AI agent system that can understand user intent, perform research, generate targeted queries, and provide relevant product recommendations in an e-commerce context using ADK and external search capabilities.\n"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "shop_agent.ipynb",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.10"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
